<?php

/**
 * Parameters holder
 *
 */
class Rapide_Parameters implements Iterator, ArrayAccess, Countable
{
	protected $_aParameters = array();

	/**
	 * Construct holder and set data
	 *
	 * @param array $aParameters
	 */
	public function __construct(array $aParameters = array())
	{
		$this->_aParameters = $aParameters;
	}

	/**
	 * Override parameters with new data
	 *
	 * @param array $aParameters
	 */
	public function init(array $aParameters)
	{
		$this->_aParameters = $aParameters;
	}

	/**
	 * Append new data to the parameters
	 *
	 * @param array $aParameters
	 */
	public function append(array $aParameters)
	{
		$this->_aParameters = array_merge_recursive($this->_aParameters, $aParameters);
	}

	/**
	 * Get array of data
	 *
	 * @return unknown
	 */
	public function getArray()
	{
		return $this->_aParameters;
	}

	/**
	 * Check if value exists
	 *
	 * @return bool
	 */
	public function has()
	{
		$aArgs = func_get_args();

		$aParameters = $this->_aParameters;

		foreach($aArgs as $iKey => $sParameter)
		{
			if(isset($aParameters[$sParameter]))
			{
				$aParameters = $aParameters[$sParameter];
				continue;
			}
			else
				return false;
		}

		return true;
	}

	/**
	 * Get a value
	 * 
	 * Method gets arguments, that represent following entries. For example:
	 * <code>$this->get('param1', 'param2', 'param3')</code>
	 * will try to get data from
	 * <code>[param1][param2][param3]</code>
	 *
	 * @return mixed value
	 */
	public function get()
	{
		$aArgs = func_get_args();
		$aParameters = $this->_aParameters;

		foreach($aArgs as $iKey => $sParameter)
		{
			if(isset($aParameters[$sParameter]))
			{
				if(is_array($aParameters[$sParameter]))
				{
					$aParameters = $aParameters[$sParameter];
					continue;
				}
				else
					return $aParameters[$sParameter];
			}
			else
				return null;
		}

		return new self($aParameters);
	}

	/**
	 * Get a value of parameter
	 *
	 * @param string $sParameter
	 * @return mixed
	 */
	public function __get($sParameter)
	{
		if(!isset($this->_aParameters[$sParameter]))
			return null;

		if(is_array($this->_aParameters[$sParameter]))
			return new self($this->_aParameters[$sParameter]);
		else
			return $this->_aParameters[$sParameter];
	}

	/**
	 * Set a value of parametr
	 *
	 * @param string $sParameter
	 * @param mixed $mValue
	 */
	public function __set($sParameter, $mValue)
	{
		$this->_aParameters[$sParameter] = $mValue;
	}

	/**
	 * Check if value is set
	 *
	 * @param string $sParameter
	 * @return bool
	 */
	public function __isset($sParameter)
	{
		return isset($this->_aParameters[$sParameter]);
	}

	/**
	 * Unset a value of parameter
	 *
	 * @param string $sParameter
	 */
	public function __unset($sParameter)
	{
		unset($this->_aParameters[$sParameter]);
	}

	// Iterator

	public function rewind()
	{
		reset($this->_aParameters);
	}

	public function key()
	{
		return key($this->_aParameters);
	}

	public function next()
	{
		return next($this->_aParameters);
	}

	public function current()
	{
		return current($this->_aParameters);
	}

	public function valid()
	{
		return ($this->current() !== false);
	}

	// ArrayAccess

	public function offsetGet($sParameter)
	{
		return $this->__get($sParameter);
	}

	public function offsetSet($sParameter, $mValue)
	{
		return $this->__set($sParameter, $mValue);
	}

	public function offsetExists($sParameter)
	{
		return $this->__isset($sParameter);
	}

	public function offsetUnset($sParameter)
	{
		unset($this->$sParameter);
	}

	// Countable

	public function count()
	{
		return count($this->_aParameters);
	}
}

?>